home *** CD-ROM | disk | FTP | other *** search
- /* Send and receive IP datagrams on serial lines. Compatible with SLIP
- * under Berkeley Unix.
- */
- #include <stdio.h>
- #include "config.h"
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "timer.h"
-
- #ifdef SLFP
- #include "ip.h"
- #include "slfp.h"
- #endif
-
- #include "ax25.h"
- #include "slip.h"
- #include "nrs.h"
- #ifdef UNIX /* BSD or SYS5 */
- #include "unix.h"
- #else
- # ifdef ATARI_ST
- # include "st.h"
- # else
- # include "pc.h"
- # include "asy.h"
- # endif /* ATARI_ST */
- #endif /* BSD or SYS5 */
- #include "trace.h"
-
- int asy_ioctl();
- int kiss_ioctl();
- int slip_send();
- int doslip();
- int asy_output();
-
- #ifdef SLFP
- int doslfp();
- int slfp_raw();
- int slfp_send();
- int slfp_recv();
- int slfp_init();
- #endif
-
- /* Slip level control structure */
- struct slip slip[ASY_MAX];
-
- /* Send routine for point-to-point slip
- * This is a trivial function since there is no slip link-level header
- */
- int
- slip_send(bp,interface,gateway,precedence,delay,throughput,reliability)
- struct mbuf *bp; /* Buffer to send */
- struct interface *interface; /* Pointer to interface control block */
- int32 gateway; /* Ignored (SLIP is point-to-point) */
- char precedence;
- char delay;
- char throughput;
- char reliability;
- {
- if(interface == NULLIF){
- free_p(bp);
- return;
- }
- dump(interface,IF_TRACE_OUT,TRACE_IP,bp);
- (*interface->raw)(interface,bp);
- }
- /* Send a raw slip frame -- also trivial */
- slip_raw(interface,bp)
- struct interface *interface;
- struct mbuf *bp;
- {
- /* Queue a frame on the slip output queue and start transmitter */
- slipq(interface->dev,bp);
- }
- /* Encode a raw packet in slip framing, put on link output queue, and kick
- * transmitter
- */
- static
- slipq(dev,bp)
- int16 dev; /* Serial line number */
- struct mbuf *bp; /* Buffer to be sent */
- {
- register struct slip *sp;
- struct mbuf *slip_encode();
-
- if((bp = slip_encode(bp)) == NULLBUF)
- return;
-
- sp = &slip[dev];
- enqueue(&sp->sndq,bp);
- sp->sndcnt++;
- if(sp->tbp == NULLBUF)
- asy_start(dev);
- }
- /* Start output, if possible, on asynch device dev */
- static
- asy_start(dev)
- int16 dev;
- {
- register struct slip *sp;
-
- if(!stxrdy(dev))
- return; /* Transmitter not ready */
-
- sp = &slip[dev];
- if(sp->tbp != NULLBUF){
- /* transmission just completed */
- free_p(sp->tbp);
- sp->tbp = NULLBUF;
- }
- if(sp->sndq == NULLBUF)
- return; /* No work */
-
- sp->tbp = dequeue(&sp->sndq);
- sp->sndcnt--;
- asy_output(dev,sp->tbp->data,sp->tbp->cnt);
- }
- /* Encode a packet in SLIP format */
- static
- struct mbuf *
- slip_encode(bp)
- struct mbuf *bp;
- {
- struct mbuf *lbp; /* Mbuf containing line-ready packet */
- register char *cp;
- register int cnt;
- char c;
-
- /* Allocate output mbuf that's twice as long as the packet.
- * This is a worst-case guess (consider a packet full of FR_ENDs!)
- */
- lbp = alloc_mbuf(2*len_mbuf(bp) + 2);
- if(lbp == NULLBUF){
- /* No space; drop */
- free_p(bp);
- return NULLBUF;
- }
- cp = lbp->data;
- cnt = 0;
-
- /* Flush out any line garbage */
- *cp++ = FR_END;
- cnt++;
-
- /* Copy input to output, escaping special characters */
- while(pullup(&bp,&c,1) == 1){
- switch(c & 0xff){
- case FR_ESC:
- *cp++ = FR_ESC;
- *cp++ = T_FR_ESC;
- cnt += 2;
- break;
- case FR_END:
- *cp++ = FR_ESC;
- *cp++ = T_FR_END;
- cnt += 2;
- break;
- default:
- *cp++ = c;
- cnt++;
- }
- }
- *cp++ = FR_END;
- cnt++;
- lbp->cnt = cnt;
- return lbp;
- }
- /* Process incoming bytes in SLIP format
- * When a buffer is complete, return it; otherwise NULLBUF
- */
- static
- struct mbuf *
- slip_decode(dev,c)
- int16 dev; /* Slip unit number */
- char c; /* Incoming character */
- {
- struct mbuf *bp;
- register struct slip *sp;
-
- sp = &slip[dev];
- switch(c & 0xff){
- case FR_END:
- bp = sp->rbp;
- sp->rbp = NULLBUF;
- sp->rcnt = 0;
- return bp; /* Will be NULLBUF if empty frame */
- case FR_ESC:
- sp->escaped = 1;
- return NULLBUF;
- }
- if(sp->escaped){
- sp->escaped = 0;
- switch(c & 0xff){
- case T_FR_ESC:
- c = FR_ESC;
- break;
- case T_FR_END:
- c = FR_END;
- break;
- default:
- sp->errors++;
- break; /* DG2KK: from .16 */
- }
- }
- /* We reach here with a character for the buffer;
- * make sure there's space for it
- */
- if(sp->rbp == NULLBUF){
- /* Allocate first mbuf for new packet */
- if((sp->rbp1 = sp->rbp = alloc_mbuf(SLIP_ALLOC)) == NULLBUF)
- return NULLBUF; /* No memory, drop */
- sp->rcp = sp->rbp->data;
- } else if(sp->rbp1->cnt == SLIP_ALLOC){
- /* Current mbuf is full; link in another */
- if((sp->rbp1->next = alloc_mbuf(SLIP_ALLOC)) == NULLBUF){
- /* No memory, drop whole thing */
- free_p(sp->rbp);
- sp->rbp = NULLBUF;
- sp->rcnt = 0;
- return NULLBUF;
- }
- sp->rbp1 = sp->rbp1->next;
- sp->rcp = sp->rbp1->data;
- }
- /* Store the character, increment fragment and total
- * byte counts
- */
- *sp->rcp++ = c;
- sp->rbp1->cnt++;
- sp->rcnt++;
- return NULLBUF;
- }
- /* Process SLIP line I/O */
- int
- doslip(interface)
- struct interface *interface;
- {
- char c;
- struct mbuf *bp;
- int16 dev;
- int16 asy_recv();
-
- dev = interface->dev;
- /* Process any pending input */
- while(asy_recv(dev,&c,1) != 0)
- if((bp = slip_decode(dev,c)) != NULLBUF)
- (*slip[dev].recv)(interface,bp);
-
- /* Kick the transmitter if it's idle */
- if(stxrdy(dev))
- asy_start(dev);
- }
- /* Unwrap incoming SLIP packets -- trivial operation since there's no
- * link level header
- */
- slip_recv(interface,bp)
- struct interface *interface;
- struct mbuf *bp;
- {
- void ip_route();
-
- /* By definition, all incoming packets are "addressed" to us */
- dump(interface,IF_TRACE_IN,TRACE_IP,bp);
- ip_route(bp,0);
- }
- /* Attach a serial interface to the system
- * argv[0]: hardware type, must be "asy"
- * argv[1]: I/O address, e.g., "0x3f8"
- * argv[2]: vector, e.g., "4"
- * argv[3]: mode, may be:
- * "slip" (point-to-point SLIP)
- * "ax25" (AX.25 frame format in SLIP for raw TNC)
- * "slfp" (point-to-point SL/FP, as used by the Merit Network and MIT)
- * "nrs" (net/rom to net/rom serial framing method)
- * argv[4]: interface label, e.g., "sl0"
- * argv[5]: receiver ring buffer size in bytes
- * argv[6]: maximum transmission unit, bytes
- * argv[7]: interface speed, e.g, "9600"
- * argv[8]: optional, may be:
- * ax.25 callsign DG2KK: new from netrom version
- * command string to MODEM, e.g. ATDT<phone number>
- */
- asy_attach(argc,argv)
- int argc;
- char *argv[];
- {
- register struct interface *if_asy;
- extern struct interface *ifaces;
- int16 dev;
- char *call; /* DG2KK: new from netrom version */
- int mode; /* " */
- int asy_init();
- int asy_send();
- int doslip();
- int asy_stop();
- int ax_send();
- int ax_output();
- int kiss_recv();
- int kiss_raw();
-
- if(nasy >= ASY_MAX){
- printf("Too many asynch controllers\n");
- return -1;
- }
- if(strcmp(argv[3],"slip") == 0)
- mode = SLIP_MODE;
- #ifdef SLFP
- else if(strcmp(argv[3],"slfp") == 0)
- mode = SLFP_MODE;
- #endif
- else if(strcmp(argv[3],"ax25") == 0)
- mode = AX25_MODE;
- #ifdef NRS
- else if(strcmp(argv[3],"nrs") == 0)
- mode = NRS_MODE;
- #endif
- else {
- printf("Mode %s unknown for interface %s\n",
- argv[3],argv[4]);
- return -1;
- }
- dev = nasy++;
- #ifdef UNIX /* BSD or SYS5 */
- asy[dev].tty = malloc(strlen(argv[2])+1);
- strcpy(asy[dev].tty, argv[2]);
- #else
-
- #ifndef ATARI_ST
- /* Initialize hardware-level control structure */
- asy[dev].addr = htoi(argv[1]);
- asy[dev].vec = htoi(argv[2]);
- #else
- /* -------- this is Atari-ST specific ---------(DG2KK)---------------------- */
- /* argv[1] (COM Port address) is the Atari device name
- * (either "AUX:" or "MIDI")
- * argv[2] (Interrupt vector) is used as a flag to indicate if
- * bytes received on that interface should be sent out on
- * another interface (1 = AUX: 3 = MIDI).
- */
- asy[dev].vec = atoi(argv[2]); /* dev to resend bytes to */
- asy[dev].addr = 0; /* use as error flag */
- if (strcmp(argv[1],"AUX:") == 0) {
- asy[dev].addr = 1;
- /* don't allow retransmission on AUX: if mode is ax25! */
- if (strcmp(argv[3],"ax25") == 0 && asy[dev].vec == 1) {
- asy[dev].vec = 0;
- }
- }
- if (strcmp(argv[1],"MIDI") == 0) {
- asy[dev].addr = 3;
- }
- if (strcmp(argv[1],"CON:") == 0) { /* this is pretty silly ! */
- asy[dev].addr = 2;
- }
- if (asy[dev].addr == 0) {
- return -1;
- }
- /* ---------- end of Atari-specific stuff ------------------------------ */
- #endif /* ATARI_ST */
-
- #endif /* BSD or SYS5 */
- /* Create interface structure and fill in details */
- if_asy = (struct interface *)calloc(1,sizeof(struct interface));
-
- if_asy->name = malloc((unsigned)strlen(argv[4])+1);
- strcpy(if_asy->name,argv[4]);
- if_asy->mtu = atoi(argv[6]);
- if_asy->dev = dev;
- if_asy->recv = doslip;
- if_asy->stop = asy_stop;
-
- if (argc == 9)
- call = argv[8];
- else
- call = NULLCHAR;
-
- switch(mode){
- case SLIP_MODE:
- if_asy->ioctl = asy_ioctl;
- if_asy->send = slip_send;
- if_asy->output = NULLFP; /* ARP isn't used */
- if_asy->raw = slip_raw;
- if_asy->flags = 0;
- slip[dev].recv = slip_recv;
- break;
- #ifdef AX25
- case AX25_MODE:
- /* This function is done in main.c so it can be easily
- * ifdef'ed out
- */
- if(kiss_attach(if_asy,&slip[dev].recv) == -1){
- free(if_asy->name);
- free((char *)if_asy);
- nasy--;
- return -1;
- }
- break;
- #endif
- #ifdef NRS
- case NRS_MODE:
- if (nrs_attach(if_asy,call) == -1) {
- free(if_asy->name);
- free((char *)if_asy);
- nasy--;
- return -1;
- }
- nrs[dev].iface = if_asy;
- break;
- #endif
- #ifdef SLFP
- case SLFP_MODE:
- if_asy->ioctl = asy_ioctl;
- if_asy->send = slfp_send;
- if_asy->recv = doslfp;
- if_asy->output = NULLFP; /* ARP isn't used */
- if_asy->raw = slfp_raw;
- if_asy->flags = 0;
- slfp[dev].recv = slfp_recv;
- break;
- #endif
- }
- if_asy->next = ifaces;
- ifaces = if_asy;
- asy_init(dev,(unsigned)atoi(argv[5]));
- asy_speed(dev,atoi(argv[7]));
- #ifdef SLFP
- if(mode == SLFP_MODE)
- if(slfp_init(if_asy, &ip_addr, argc>7?argv[8]:NULLCHAR) == -1) {
- printf("Request for IP address timed out.\n");
- asy_stop(if_asy);
- ifaces = if_asy->next;
- free((char *)if_asy);
- return -1;
- }
- #endif
- return 0;
- }
-